/*
 * xWindow 1.0 - Plugin for jQuery
 * 
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Depends:
 *   jquery.js
 *	 ui.base.js
 * 	 ui.draggable.js
 *   ui.resizable.js
 * 
 *
 *  Copyright (c) 2008 Oleg Slobodskoi (ajaxsoft.de)
 */


;(function($){


	$.fn.extend({
		xWindow: function( options ) {
		
			var	args = Array.prototype.slice.call(arguments, 1);

			return this.each(function() {
				var method = (typeof options == 'string') ? options : 'init',
					xWindow = $.data(this, 'xWindow') || $.data( this, 'xWindow', new $.xWindow(this, options));
				xWindow[method].apply(xWindow, args);
			});
	

		}
	});


	$.xWindow = function(elem, options)
	{

		/**************************************************************************/
		//Defaults

		var d = {
			title: '',
			status: '',
			position: 'center',
			width: 320,
			height: 240,
			content: null,
			draggable: true,
			resizable: true,
			closable: true,
			maximizable: true,
			minimizable: true,
			autoShow: true,
			close: function(){},
			resize: function(){},
			restoreAfterDestroy: false,
			modal: false,
			overlayOpacity: 0.7,
			stayInView: false,
			draggableOptions: {
				cancel: '.xWindow-content,.xWindow-titlebar-btn',
				helper: 'clone', //or original || clone
				opacity: 0.7,
				scroll: true,
				scrollSensitivity: 80,
				scrollSpeed: 20
			},
			resizableOptions: {
				cancel: '.xWindow-content',
				maxWidth: null,
				maxHeight: null,
				minWidth: 200,
				minHeight: 100,
				containment: null,
				helper: 'xWindow-resizable-proxy'		
			},			
			titlebar: true,
			statusbar: true,
			animate: false,
			showAnimation: {opacity: "show"},
			closeAnimation: {opacity: "hide"},
			mimimizeAnimation: null,
			maximizeAnimation: null,
			speed: 200,
			extension: false,
			buttons: null,
			bgiframe: false
			
		};
		$.extend(d, options);
		
		
		/**************************************************************************/
		//Privat variables

		var 
			$elem = $(elem),
			$xWindow,
			$title,
			$titlebar,
			$titlebarButtons,
			$buttonsPanel,
			$status,
			$statusbar,
			$overlay,
			$bgiframe,
			$wnd = $(window), 
			$doc = $(document),
			self = this,
			size = {
				width: d.width,
				height: d.height
			},
			pos = d.position,
			savedPos = {},
			savedSize = {},
			statusbarHeight,
			titlebarHeight,
			buttonsPanelHeight
		;
	

		/**************************************************************************/
		//Public variables

		this.$elem = $elem;
		this.$xWindow = $xWindow;
		this.mimimized = false;
		this.maximized = false;
		this.contentSize = {};
		this.buttons = {};
		this.createCallback = createCallback;

		/**************************************************************************/
		//Public methods
		this.init = function()
		{
			create();
			d.autoShow && self.show();

			//fix selectboxes in IE6
			if (d.bgiframe && $.fn.bgiframe)
			{
				$xWindow.bgiframe();
				$bgiframe = $xWindow.children('.bgiframe');
			};
			
			$doc.keydown(function(e) {
				if ($xWindow.hasClass('selected') && e.keyCode)
				{
					var ESC = 27, enter = 13;
					e.keyCode == ESC && self.destroy();
					e.keyCode == enter && $buttonsPanel && $buttonsPanel.children('.focus').click();
				};
			});
			

		};

		this.object = function ( callback )
		{
			createCallback(callback, [self]);
		};
		
		this.defaults = function ( param )
		{
			typeof param == 'object' ? $.extend(d, param) : createCallback(param, [d]);
		};

		this.title = function ( param )
		{
			/^[\s[]?function/.test( param + "" ) ? createCallback(param, [$title.text()]) :  $title.text(param);
		};

		this.status = function ( param )
		{
			/^[\s[]?function/.test( param + "" ) ? createCallback(param, [$status.text()]) :  $status.text(param);
		};		

		this.position = function ( param ) 
		{
			typeof param == 'object' ? position(param) : createCallback(param, [pos]);
		};
		
		this.size = function( param )
		{
			typeof param == 'object' ? resize(param) : createCallback(param, [size]);
		};

		//toggle minimize
		this.minimize = function()
		{
			//restore normal state 
			self.maximized && self.maximize();
			
			//minimize window
			if (!self.minimized)
			{
				saveSize(size);
				$statusbar && $statusbar.hide();
				$buttonsPanel && $buttonsPanel.hide();
				resize({width: size.width , height: $titlebar.height()});
				self.minimized=true;
			} 
			//restore window
			else
			{
				restoreSize();
				resize(size);
				$statusbar && $statusbar.show();
				$buttonsPanel && $buttonsPanel.show();
				self.minimized = false;
			};
		};		
		
		//toggle fullscreen
		this.maximize = function()
		{
			//restore normal state 
			self.minimized && self.minimize();
			
			//fullscreen window
			if (!self.maximized)
			{
				saveSize(size);
				savePos(pos);
				position({top: 5, left: 5});
				resize({width: $wnd.width()-10, height: $wnd.height()-10});
				self.maximized=true;
			} 
			//restore window
			else
			{
				restoreSize();
				restorePos();
				$xWindow.css(pos)
				resize(size);
				self.maximized=false;
			};
						
		};
		
		this.show = function()
		{
			d.animate && d.showAnimation ? $xWindow.animate(d.showAnimation, d.speed) : $xWindow.show();
			self.select();
			titlebarHeight = $titlebar ? $titlebar.height() : 0;
			buttonsPanelHeight = $buttonsPanel ? $buttonsPanel.height() : 0;			
			statusbarHeight = $statusbar ? $statusbar.height() : 0;
			resize({width: d.width, height: d.height});
			position(d.position);			
		};

		this.destroy = function()
		{	
			d.restoreAfterDestroy && $elem.removeClass('xWindow-content').hide().appendTo('body');
			$.removeData($elem);			
			$titlebar && $.removeData($titlebar, "ui-mouse");			
			$statusbar && $.removeData($statusbar, "ui-mouse");			
			$overlay && $overlay.remove();
			$.removeData($elem.get(0), 'xWindow');

			d.animate && d.closeAnimation ? $xWindow.animate(d.closeAnimation, d.speed, function(){
				$xWindow.remove();
				createCallback(d.onClose, [self]);
			}) : $xWindow.remove();

			createCallback(d.close, [self]);
		};

		this.hide = function()
		{
			d.animate && d.closeAnimation ? $xWindow.animate(d.closeAnimation, d.speed) : $xWindow.hide();
			createCallback(d.onClose, [self]);
		};		

		this.select = function()
		{
			$('.xWindow:visible').removeClass('selected');
			$xWindow.addClass('selected');
		};		
		
		this.buttonEnabled = function (buttonName, sw)
		{
			var action = sw ? 'removeClass' : 'addClass';
			self.buttons[buttonName].$elem[action]('disabled');
		};


		/**************************************************************************/
		//Private methods
		function create ()
		{
			$xWindow = $('<div class="xWindow selected"/>');
			d.extension && $xWindow.addClass('xWindow-extended '+ d.extension);

			//add titlebar
			d.titlebar && titlebar(d.title || $elem.attr('title'));
			
			//add user container
			$elem.addClass('xWindow-content').show().
			appendTo($xWindow);			
			
			//add buttons
			d.buttons && buttons(d.buttons);

			//add status Bar
			d.statusbar ? statusbar(d.status) : $xWindow.addClass('no-xWindow-statusbar');
			
			//set on top by click on each element
			$xWindow.children().mousedown(self.select);			
			
			//add content
			d.content && $elem.html(d.content);

			//stayInView
			(d.stayInView || d.modal) && $doc.scroll(function(){position('center')});
			
			//make it draggable
			d.draggable && $.fn.draggable && draggable();

			//make it resizable
			d.resizable && $.fn.resizable && $statusbar && resizable();

			//show overlay if modal
			if (d.modal)
			{
				if ($('.xWindow-overlay').length>0)
					var opacity = 0.01;
				$overlay = $('<div class="xWindow-overlay"/>').
				css({'opacity':opacity || d.overlayOpacity, 'height' : $wnd.height()}).
				appendTo('body');
				d.bgiframe && $.fn.bgiframe && $overlay.bgiframe();
			};
			$xWindow.appendTo('body');
			
			$wnd.resize(windowResize);
		};
		
		function windowResize ()
		{
			//resize overlay
			$overlay && $overlay.height($wnd.height());
			position(d.position);
		};
		
		
		function resize (s)
		{
			$.extend(size, s);
			$xWindow.css(size);
			initContentSize();
			createCallback(d.resize, [self]);
		};		

		function initContentSize ()
		{
			self.contentSize.height  = size.height-titlebarHeight-statusbarHeight - buttonsPanelHeight;
			self.contentSize.width = size.width;
			$elem.height(self.contentSize.height);
		};

		function titlebar (title)
		{
			$titlebar = $('<div class="xWindow-titlebar"/>').appendTo($xWindow);
			$title = $('<span class="title">'+title+'</span>').appendTo($titlebar);
			d.title = title;
			
			//add panel for titlebar buttons
			if (d.closable || d.minimizable || d.maximizable)
				$titlebarButtons = $('<div class="xWindow-titlebar-buttons-panel"/>').
				appendTo($titlebar);
			
			d.closable &&
			$('<div class="xWindow-close-btn xWindow-titlebar-btn"/>').
			appendTo($titlebarButtons).
			click(self.destroy);

			d.maximizable &&
			$('<div class="xWindow-maximize-btn xWindow-titlebar-btn"/>').
			appendTo($titlebarButtons).
			click(self.maximize);

			d.minimizable &&
			$('<div class="xWindow-minimize-btn xWindow-titlebar-btn"/>').
			appendTo($titlebarButtons).
			click(self.minimize);		

		};
		
		function buttons (btns)
		{
			if  (!btns) return;

			$buttonsPanel = $('<div class="xWindow-buttons-panel"/>');
			var $container = $('<div/>'), $button;

			var i=0;
			$.each(btns, function(name,val){
				$button = $('<a class="button" href="#">'+val.title+'</a>');
				val.focus && $button.addClass('focus').focus();
				val.disabled && $button.addClass('disabled');
				i>0 && $button.addClass('margin');
				
				$button.click(function (){ 
					!$(this).hasClass('disabled') && createCallback(val.onclick);
					return false;
				}).appendTo($container);
				$.extend(self.buttons[i], val, {$elem: $button});
				i++;
			});	

			$container.appendTo($buttonsPanel);
			$buttonsPanel.appendTo($xWindow);
		};
		
		function statusbar (status)
		{
			$statusbar = $('<div class="xWindow-statusbar"/>').
			appendTo($xWindow);	
			$status = $('<span>'+status+'</span>').appendTo($statusbar);
		};
		
		function draggable ()
		{
			var dragHandles = [];
			$titlebar && dragHandles.push($titlebar.get(0));
			$statusbar && dragHandles.push($statusbar.get(0));
			if (dragHandles.length>0) 
			{
				$.extend(d.draggableOptions, {
					handle : dragHandles,
					start: function(e,obj)
					{
							obj.helper.children('.xWindow-content').remove();
							$xWindow.hide();
							$bgiframe && $bgiframe.remove();
					},
					stop: function(e,obj)
					{
						position({top:obj.position.top-$doc.scrollTop(),left:obj.position.left-$doc.scrollLeft()});
						$xWindow.show();
						d.bgiframe && $xWindow.bgiframe();
					}
				});
				$xWindow.draggable(d.draggableOptions);
			};
		
		};
		
		function resizable ()
		{
			$.extend(d.resizableOptions, {
				handles : {
					se: $('<div class="ui-resizable-se ui-resizable-handle"/>').appendTo($statusbar)
				},
				stop: function(e, obj){
					resize({width: obj.size.width, height: obj.size.height});
				}
			});

			$xWindow.resizable(d.resizableOptions);		
		};
		

		
		function position (p)
		{
			var scrTop = $doc.scrollTop(), scrLeft = $doc.scrollLeft();
				

			if (typeof p == 'object')
			{
				p = {
					left: p.left ? scrLeft+p.left : null, 
					top: p.top ? scrTop+p.top : null,
					right: p.right ? scrLeft+p.right : null,
					bottom: p.bottom ? scrLeft+p.bottom : null
				};
			} else if (p == 'center') {
				var top = Math.round(scrTop + ($wnd.height() - size.height)/2),
					left = Math.round(scrLeft + ($wnd.width() - size.width)/2);
				p = {
					top: top>0 ? top : 0,
					left: left>0 ? left : 0
				};
			};

			pos = $.extend({position: 'absolute'}, p);
			$xWindow.css(pos);	
		};
		
		function savePos ( p )
		{	
			$.extend(savedPos,p);
		};
		
		function saveSize ( s )
		{
			$.extend(savedSize,s);
		};
		
		function restorePos ()
		{
			var prevPos = $.extend({},savedPos);
			$.extend(savedPos, pos);
			$.extend(pos,prevPos);
		};

		function restoreSize ()
		{
			var prevSize = $.extend({},savedSize);
			$.extend(savedSize, size);
			$.extend(size,prevSize);
		};
		
		function createCallback (fn,params)
		{	
			typeof fn == 'string' && eval('fn='+fn);
			typeof fn == 'function' && fn.apply(self,params || []);
		};		

	
	};



})(jQuery);		